<!-- FileUpload.vue -->
<template>
	<view>
		<!-- 1. 统一的上传入口，仅在未选择任何文件时显示 -->
		<view class="upload-trigger-wrapper">
			<view v-if="fileList.length === 0 && videoList.length === 0" class="upload" @click="openUploadActionSheet">
				<u-icon class="slot-icon" name="plus" color="#999999" size="30"></u-icon>
				<view>{{ uploadText }}</view>
			</view>
		</view>

		<!-- 2. 图片上传与预览区域，仅当有图片文件时显示 -->
		<u-upload v-if="fileList.length > 0" :fileList="fileList" :maxCount="maxCount" :previewFullImage="true" name="1"
			ref="uUploadImage" multiple width="100" height="100" @afterRead="handleImageUpload" @delete="deletePic">
		</u-upload>

		<!-- 3. 视频预览区域，仅当有视频文件时显示 -->
		<view v-if="videoList.length > 0" class="video-preview-container">
			<DomVideoPlayer 
				:src="videoList[0].url" 
				:autoplay="false" 
				:controls="videoList[0].status === 'success'" 
				:muted="true" 
				object-fit="cover"
				:show-center-play-btn="false" 
				class="video" 
			/>
			
			<!-- 转码/上传状态提示 -->
			<view v-if="videoList[0].status !== 'success'" class="processing-overlay">
				<u-loading-icon size="20" color="#ffffff"></u-loading-icon>
				<text class="processing-text">{{ videoList[0].message }}</text>
			</view>
			
			<view class="delete-video-icon" @click="deleteVideoPic({index: 0})">
				<u-icon name="close" color="#ffffff" size="12"></u-icon>
			</view>
		</view>

		<!-- 上传选项弹窗 -->
		<u-action-sheet style="z-index: 99999;" :show="showUploadOptions" :actions="uploadActions" cancelText="取消"
			@select="handleUploadSelect" @close="showUploadOptions = false"></u-action-sheet>

		<!-- 全屏遮罩loading，阻止用户操作 -->
		<view v-if="isFullScreenLoading" class="fullscreen-loading">
			<view class="loading-content">
				<u-loading-icon size="40" color="#ffffff"></u-loading-icon>
				<text class="loading-text">{{ loadingText }}</text>
			</view>
		</view>
	</view>
</template>

<script>
	import config from '@/config/index.js'
	import {
		revokeFile,
		getQiniuToken
	} from '@/request/api.js'

	// 常量定义
	const POST_IMAGE_PURPOSE = 'post_image';
	const POST_VIDEO_PURPOSE = 'post_video';
	const MAX_VIDEO_SIZE_MB = 100;
	const MAX_VIDEO_SIZE_BYTES = MAX_VIDEO_SIZE_MB * 1024 * 1024;

	// 上传操作配置
	const UPLOAD_ACTIONS = [{
			name: '从相册选择照片',
			type: 'image',
			sourceType: ['album']
		},
		{
			name: '从相册选择视频',
			type: 'video',
			sourceType: ['album']
		},
		{
			name: '拍照',
			type: 'image',
			sourceType: ['camera']
		},
		{
			name: '录像',
			type: 'video',
			sourceType: ['camera']
		}
	];

	export default {
		name: 'FileUpload',
		props: {
			// 上传类型：'post' 普通发布，'voucher' 凭证上传
			uploadType: {
				type: String,
				default: 'post'
			},
			// 最大文件数量
			maxCount: {
				type: Number,
				default: 10
			},
			// 上传按钮文字
			uploadText: {
				type: String,
				default: '照片/视频'
			},
			// 初始文件列表
			initialFileList: {
				type: Array,
				default: () => []
			},
			// 初始视频列表
			initialVideoList: {
				type: Array,
				default: () => []
			}
		},
		data() {
			return {
				// 上传相关
				showUploadOptions: false,
				uploadActions: UPLOAD_ACTIONS,
				acceptType: "image",
				fileList: [],
				videoList: [],
				isUploadingGlobally: false,
				uploadToken: null,
				uploadKey: null,
				isUpLoadVideo: false,
				// 全屏loading相关
				isFullScreenLoading: false,
				loadingText: '处理中...'
			}
		},
		watch: {
			initialFileList: {
				handler(newVal) {
					this.fileList = [...newVal];
				},
				immediate: true
			},
			initialVideoList: {
				handler(newVal) {
					this.videoList = [...newVal];
				},
				immediate: true
			}
		},
		computed: {
			// 计算当前是否正在上传
			isUploading() {
				return this.isUploadingGlobally ||
					this.fileList.some(item => item.status === 'uploading') ||
					this.videoList.some(item => item.status === 'uploading') ||
					this.isFullScreenLoading;
			},
			// 计算上传成功的文件列表
			successFiles() {
				return this.fileList.filter(item => item.status === 'success');
			},
			// 计算上传成功的视频列表
			successVideos() {
				return this.videoList.filter(item => item.status === 'success');
			}
		},
		methods: {
			// ==================== 工具方法 ====================
			showToast(message, icon = 'none') {
				uni.showToast({
					title: message,
					icon,
					duration: 3000
				});
			},

			// 显示全屏loading
			showFullScreenLoading(text = '处理中...') {
				this.isFullScreenLoading = true;
				this.loadingText = text;
				// 禁用页面滚动
				uni.pageScrollTo({
					scrollTop: 0,
					duration: 0
				});
			},

			// 隐藏全屏loading
			hideFullScreenLoading() {
				this.isFullScreenLoading = false;
				this.loadingText = '处理中...';
			},

			isImageUrl(url) {
				if (!url) return false;
				const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.tif', '.webp', '.svg', '.raw',
					'.heic'
				];
				const cleanUrl = url.split('?')[0].toLowerCase();
				return imageExtensions.some(ext => cleanUrl.endsWith(ext));
			},

			// ==================== 视频转码方法 ====================
			async transcodeVideoToH264(filePath) {
				return new Promise((resolve, reject) => {
					uni.compressVideo({
						src: filePath,
						quality: 'high',
						codec: 'h264',
						success: (res) => {
							console.log('视频转码成功:', res.tempFilePath);
							resolve(res.tempFilePath);                                                                                                       
						},
						fail: (err) => {
							console.error('视频转码失败:', err);
							// 转码失败时使用原文件继续上传
							console.log('转码失败，使用原文件上传');
							resolve(filePath);
						}
					});
				});
			},

			// 清理临时文件
			cleanupTempFile(filePath) {
				if (filePath && filePath.startsWith('http://tmp/')) {
					try {
						uni.getFileSystemManager().unlink({
							filePath: filePath,
							fail: (err) => {
								console.warn('清理临时文件失败:', err);
							}
						});
					} catch (e) {
						console.warn('清理临时文件异常:', e);
					}
				}
			},

			// ==================== 上传相关方法 ====================
			openUploadActionSheet() {
				// 如果正在处理中，不允许打开上传选项
				if (this.isUploading) {
					this.showToast('正在处理中，请稍后...');
					return;
				}
				this.showUploadOptions = true;
			},

			handleUploadSelect(action) {
				if (action.type == 'video') {
					this.isUpLoadVideo = true;
					this.$emit('video-upload-start');
				}

				const config = {
					image: {
						method: 'chooseImage',
						params: {
							count: this.maxCount - this.fileList.length,
							sourceType: action.sourceType,
							sizeType: ['compressed'],
						}
					},
					video: {
						method: 'chooseVideo',
						params: {
							sourceType: action.sourceType
						}
					}
				} [action.type];

				if (!config) return;

				uni[config.method]({
					...config.params,
					success: (res) => {
						const files = action.type === 'image' ?
							res.tempFiles.map(f => ({
								url: f.path,
								...f
							})) : [{
								url: res.tempFilePath,
								width: res.width,
								height: res.height,
								...res
							}];

						const handler = action.type === 'image' ? 'handleImageUpload' : 'handleVideoUpload';
						this[handler]({
							file: files
						});
					},
					fail: (err) => {
						console.error('选择文件失败:', err);
						this.showToast('选择文件失败');
					}
				});
			},

			// ==================== 图片上传方法（通过服务器接口）====================
			async uploadFileToQiniu(fileUrl, purpose) {
				return new Promise((resolve, reject) => {
					const base_url = config.baseURL
					uni.uploadFile({
						url: base_url + '/qnyUpload/upload',
						filePath: fileUrl,
						name: "file",
						header: {
							'Authorization': uni.getStorageSync('token') || '',
							'Accept': 'application/json'
						},
						success: (res) => {
							if (res.statusCode === 413) {
								reject(new Error('文件大小超过服务器限制，请选择较小的文件'));
								return;
							}
							try {
								const responseData = typeof res.data === 'string' ? JSON.parse(res
									.data) : res.data;
								if (responseData.code === 200) {
									const imageUrl = responseData.url;
									resolve(imageUrl);
								} else {
									reject(new Error(responseData.msg || '上传失败'));
								}
							} catch (error) {
								reject(new Error('服务器响应格式错误'));
							}
						},
						fail: (err) => {
							if (err.errMsg && err.errMsg.includes('request:fail')) {
								reject(new Error('网络连接失败，请检查网络设置'));
							} else {
								reject(new Error('网络请求失败'));
							}
						}
					});
				});
			},

			// ==================== 视频上传方法（直接上传到七牛云）====================
			async generateQiniuToken(originalFilename, purpose) {
				try {
					const params = {
						originalFilename,
						purpose
					};
					const res = await getQiniuToken(params);

					if (res.data?.data?.token) {
						this.uploadToken = res.data.data.token;
						this.uploadKey = res.data.data.key;
						return true;
					} else {
						throw new Error('Failed to get Qiniu token');
					}
				} catch (error) {
					this.showToast('获取上传凭证失败');
					throw error;
				}
			},

			async uploadVideoToQiniu(fileUrl) {
				return new Promise((resolve, reject) => {
					uni.uploadFile({
						url: this.$store.state.qiNiuUploadUrl,
						filePath: fileUrl,
						name: "file",
						formData: {
							token: this.uploadToken,
							key: this.uploadKey,
						},
						success: (res) => {
							try {
								const data = JSON.parse(res.data);
								resolve(`${this.$store.state.ossBaseUrl}/${data.key}`);
							} catch (e) {
								reject(new Error('Upload response parsing error'));
							}
						},
						fail: reject
					});
				});
			},

			// 统一的文件上传处理
			async handleFileUpload({
				file,
				isVoucher = false
			}) {
				// 如果正在处理中，不允许重复上传
				if (this.isUploading) {
					this.showToast('正在处理中，请稍后...');
					return;
				}

				const lists = [].concat(file);
				if (lists.length === 0) return;

				// 清理冲突的文件类型
				if (this.fileList.length > 0 && lists[0].type?.includes('video')) {
					this.showToast('只能上传图片或视频之一，已为您清空图片', 'none');
					this.fileList = [];
				}

				// 判断文件类型
				if (lists[0].tempFile && lists[0].tempFile.type) {
					this.acceptType = 'video'
				} else if (lists[0].tempFilePath && lists[0].tempFilePath.includes('mp4')) {
					this.acceptType = 'video'
				} else {
					this.acceptType = 'image'
				}

				if (this.acceptType === 'video') {
					await this.handleVideoFileUpload(lists[0]);
				} else {
					await this.handleImageFilesUpload(lists);
				}
			},

			async handleVideoFileUpload(fileItem) {
				const fileSize = fileItem.size || (fileItem.file ? fileItem.file.size : 0);

				if (fileSize > MAX_VIDEO_SIZE_BYTES) {
					this.showToast(`视频文件最大支持${MAX_VIDEO_SIZE_MB}MB`, 'none');
					this.videoList = [{
						url: fileItem.url,
						status: 'fail',
						message: `超过${MAX_VIDEO_SIZE_MB}MB限制`
					}];
					return;
				}

				const originalName = fileItem.name || `video_${Date.now()}.${fileItem.url.split('.').pop() || 'mp4'}`;
				const mimeType = fileItem.type || 'video/mp4';

				const videoObject = {
					url: fileItem.url,
					width: fileItem.width,
					height: fileItem.height,
					status: 'transcoding', // 初始状态为转码中
					message: '视频转码中...',
					originalName,
					mimeType,
					qiniuKey: null
				};

				this.videoList = [videoObject];
				await this.uploadSingleVideoFile(fileItem.url, originalName, 0);
			},

			async handleImageFilesUpload(lists) {
				this.showFullScreenLoading('图片上传中...');
				this.isUploadingGlobally = true;

				const newFilePlaceholders = lists.map(item => ({
					url: item.url,
					status: "uploading",
					message: "上传中...",
					originalName: item.name || `image_${Date.now()}.${item.url.split('.').pop() || 'jpg'}`,
					mimeType: item.type || 'image/jpeg',
					qiniuKey: null,
					_tempPath: item.url
				}));

				this.fileList.push(...newFilePlaceholders);

				try {
					await Promise.all(newFilePlaceholders.map(async (placeholder) => {
						const currentIndex = this.fileList.indexOf(placeholder);
						await this.uploadSingleImageFile(
							placeholder._tempPath,
							placeholder.originalName,
							currentIndex
						);
					}));
				} finally {
					this.isUploadingGlobally = false;
					this.hideFullScreenLoading();
				}
			},

			// 图片上传（通过服务器接口）
			async uploadSingleImageFile(fileUrl, originalName, index) {
				try {
					const qiniuCdnUrl = await this.uploadFileToQiniu(fileUrl, POST_IMAGE_PURPOSE);
					const updatedFile = {
						...this.fileList[index],
						url: qiniuCdnUrl,
						status: 'success',
						message: '上传成功',
						qiniuKey: this.uploadKey
					};

					this.$set(this.fileList, index, updatedFile);
					this.$emit('upload-success', updatedFile);
				} catch (error) {
					this.fileList.splice(index, 1);
					this.showToast(error.message || `文件上传失败`);
					this.$emit('upload-error', error);
				}
			},

			// 视频上传（包含转码逻辑）
			async uploadSingleVideoFile(fileUrl, originalName, index) {
				try {
					// 显示全屏loading
					this.showFullScreenLoading('视频转码中...');

					// 更新状态为转码中
					// this.$set(this.videoList, index, {
					// 	...this.videoList[index],
					// 	status: 'transcoding',
					// 	message: '视频转码中...'
					// });

					// 1. 先进行视频转码为H.264
					// const transcodedFilePath = await this.transcodeVideoToH264(fileUrl);
					const transcodedFilePath = fileUrl;
					
					// 更新loading文本
					this.showFullScreenLoading('视频上传中...');
					
					// 更新状态为上传中
					this.$set(this.videoList, index, {
						...this.videoList[index],
						status: 'uploading',
						message: '上传中...'
					});

					// 2. 获取七牛云上传凭证
					await this.generateQiniuToken(originalName, POST_VIDEO_PURPOSE);
					
					// 3. 上传转码后的视频
					const qiniuCdnUrl = await this.uploadVideoToQiniu(transcodedFilePath);

					const updatedFile = {
						...this.videoList[index],
						url: qiniuCdnUrl,
						status: 'success',
						message: '上传成功',
						qiniuKey: this.uploadKey,
						originalPath: fileUrl, // 保存原始路径
						transcodedPath: transcodedFilePath // 保存转码后路径
					};

					this.$set(this.videoList, index, updatedFile);
					this.$emit('upload-success', updatedFile);
					
					// 清理临时转码文件
					setTimeout(() => {
						this.cleanupTempFile(transcodedFilePath);
					}, 5000);
					
				} catch (error) {
					console.error('视频上传错误:', error);
					this.videoList.splice(index, 1);
					this.showToast(error.message || `视频处理失败`);
					this.$emit('upload-error', error);
				} finally {
					// 无论成功失败，都隐藏loading
					this.hideFullScreenLoading();
				}
			},

			// 简化的上传处理方法
			async handleImageUpload(event) {
				await this.handleFileUpload({
					file: event.file
				});
			},

			async handleVideoUpload(event) {
				await this.handleFileUpload({
					file: event.file
				});
			},

			// ==================== 删除方法 ====================
			deletePic(event) {
				// 如果正在处理中，不允许删除
				if (this.isUploading) {
					this.showToast('正在处理中，请稍后...');
					return;
				}
				const fileToDelete = this.fileList[event.index];
				if (fileToDelete.qiniuKey) {
					this.fileList.splice(event.index, 1);
				} else {
					this.fileList.splice(event.index, 1);
					this.showToast('图片已从列表移除');
				}
				this.$emit('file-deleted', fileToDelete);
			},

			deleteVideoPic(event) {
				// 如果正在处理中，不允许删除
				if (this.isUploading) {
					this.showToast('正在处理中，请稍后...');
					return;
				}
				const fileToDelete = this.videoList[event.index];
				if (fileToDelete.qiniuKey) {
					this.videoList.splice(event.index, 1);
					this.$emit('file-deleted', fileToDelete);
				} else {
					this.videoList.splice(event.index, 1);
					this.showToast('视频已从列表移除');
					this.$emit('file-deleted', fileToDelete);
				}
			},

			// ==================== 公共方法 ====================
			// 获取上传成功的文件列表
			getSuccessFiles() {
				return {
					files: this.successFiles,
					videos: this.successVideos,
					acceptType: this.acceptType
				}
			},

			// 清空文件列表
			clearFiles() {
				// 如果正在处理中，不允许清空
				if (this.isUploading) {
					this.showToast('正在处理中，请稍后...');
					return;
				}
				this.fileList = [];
				this.videoList = [];
				this.acceptType = 'image';
			},

			// 检查是否正在上传
			checkUploading() {
				return this.isUploading;
			},

			// 检查是否有视频上传
			hasVideoUpload() {
				return this.isUpLoadVideo;
			}
		}
	}
</script>

<style lang="scss">
	/* 确保 ActionSheet 显示在最上层 */
	::v-deep .u-action-sheet {
		z-index: 10002 !important;
	}

	::v-deep .u-popup {
		z-index: 10002 !important;
	}

	.upload {
		width: 100px;
		height: 100px;
		background: #F8F8F8;
		color: #7C7B7B;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		font-size: 26rpx;
		border-radius: 20rpx;
	}

	.video {
		max-width: 360px;
	}

	.upload-trigger-wrapper {
		// 布局样式
	}

	.video-preview-container {
		position: relative;
		width: 360rpx;
		height: 360rpx;
		margin-bottom: 20rpx;

		.video {
			width: 100%;
			height: 100%;
			border-radius: 20rpx;
		}

		.delete-video-icon {
			position: absolute;
			top: 10rpx;
			right: 10rpx;
			width: 40rpx;
			height: 40rpx;
			background-color: rgba(0, 0, 0, 0.5);
			border-radius: 50%;
			display: flex;
			justify-content: center;
			align-items: center;
			z-index: 10;
		}

		.processing-overlay {
			position: absolute;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			background-color: rgba(0, 0, 0, 0.7);
			display: flex;
			flex-direction: column;
			justify-content: center;
			align-items: center;
			border-radius: 20rpx;
			z-index: 5;
		}

		.processing-text {
			color: #ffffff;
			font-size: 24rpx;
			margin-top: 10rpx;
		}
	}

	/* 全屏loading样式 */
	.fullscreen-loading {
		position: fixed;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		background-color: rgba(0, 0, 0, 0.7);
		display: flex;
		justify-content: center;
		align-items: center;
		z-index: 99999;
	}

	.loading-content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		background-color: rgba(0, 0, 0, 0.8);
		padding: 40rpx;
		border-radius: 20rpx;
		min-width: 300rpx;
	}

	.loading-text {
		color: #ffffff;
		font-size: 28rpx;
		margin-top: 20rpx;
		text-align: center;
	}
</style>